package battleship;

/**
 *
 * @author HUBERT Jean-Philippe <jean-philippe.hubert@uqac.ca>
 * UQAC - Université du Québec à Chicoutimi
 *
 */
public class Regle {
    //Préconditions
    private boolean      bateauTouche;
    private boolean      coule;
    private boolean      manque;
    private boolean      touche;
    //Référence vers le moteur d'inférence
    private IABattleShip parent;

    private boolean      marquee;
    private int          consequence;

    /**
     *
     * @param manque precondition caracterisant la premisse de la regle
     * @param touche precondition caracterisant la premisse de la regle
     * @param bateauTouche precondition caracterisant la premisse de la regle
     * @param coule precondition caracterisant la premisse de la regle
     * @param consequence numero de la consequence a adopter si la regle est appliquée
     * @param parent référence vers le moteur d'inférence
     */
    public Regle(boolean manque, boolean touche, boolean bateauTouche, boolean coule, int consequence,IABattleShip parent) {

        initRegle(manque, touche, bateauTouche, coule, consequence);

        if (parent == null) {
            throw new NullPointerException("parent null -_-");
        }

        this.parent = parent;
    }

    /**
     * Initialisation des membres.
     * Valeurs par defaut.
     *
     */
    private void initRegle() {
        this.coule  = false;
        this.manque = false;
        this.touche = false;
        this.bateauTouche = false;
        this.setMarque(false);
    }

    private void initRegle(boolean manque, boolean touche, boolean bateauTouche, boolean coule, int consequence) {
        this.coule  = coule;
        this.manque = manque;
        this.touche = touche;
        this.bateauTouche = bateauTouche;
        this.setMarque(false);
        this.consequence = consequence;
    }

    /**
     * Modificateur du booléen marquee
     *
     * @param marquee 
     */
    public void setMarque(boolean marquee) {
        this.marquee = marquee;
    }
    
    // VALIDATION DES PRECONDITIONS FORMANT LES PREMISSES
    /**
     * Cette precondition est valide si lors du dernier coup, l'IA a coule
     * un bateau
     *
     * @return precondition "coule"
     *
     */
    private boolean estCoule() {
        for (int k = 0; k < this.parent.listeBateaux.length; k++) {
            if (this.parent.listeBateaux[k].getTourCoule() == 1) {
                return true;
            }
        }

        return false;
    }

    /**
     * Cette precondition est valide si un bateau a ete touche
     * Donc si on trouve une case dont le code est : 'f', 'g', 'h', 'i', 'j'.
     *
     * @return precondition "touche"
     */
    private boolean estTouche() {
        for (int k = 0; k < this.parent.listeBateaux.length; k++) {
            if ((this.parent.listeBateaux[k].getEtat() < this.parent.listeBateaux[k].getLongueur())
                    && (this.parent.listeBateaux[k].getEtat() >= 0)
                    && this.parent.connaissanceIA.chercheCaseTouche(1)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Cette precondition est valide si l'IA a raté son coup au dernier tour
     *
     * @return precondition "manque"
     */
    private boolean aManque() {
        return this.parent.connaissanceIA.chercheCase('o', 1);
    }

    /**
     * Cette precondition est valide si l'IA a touche un bateau qui n'est pas encore coule
     *
     * @return precondition "bateauTouche"
     */
    private boolean aBateauTouche() {
        for (int k = 0; k < this.parent.listeBateaux.length; k++) {
            if ((this.parent.listeBateaux[k].getEtat() >= 0)
                    && (this.parent.listeBateaux[k].getEtat() != this.parent.listeBateaux[k].getLongueur())) {
                return true;
            }
        }

        return false;
    }


    /**
     * Informe sur la validité de la regle
     *
     * @return
     */
    public boolean verifier() {
        if ((this.estCoule() == this.coule) && (this.estTouche() == this.touche) && (this.aManque() == this.manque)
                && (this.aBateauTouche() == this.bateauTouche)) {
            return true;
        }

        return false;
    }

    /**
     *
     * @return applicabilite de la regle
     */
    public boolean estAplicable(){
        return !this.marquee && this.verifier();
    }



    //CONSEQUENCES DE LA REGLE
    
    public void appliquerConsequence(){
        switch (this.consequence){
            //On relance aleatoirement R1
            case 1:
                joueAleatoire();
                break;
            //On a trouve une case et on empile la ligne et la colonne
            case 2:
                int[] coord = new int[2];
                coord = this.parent.connaissanceIA.derniereCase();
                this.parent.joueLigneColonne(coord[0], coord[1]);
                break;
            case 3:
                //Si on a un bateau à chasser, on retrouve sa derniere position connue et on joue autour
                if (this.parent.fileCaseAJouer.isEmpty() && !this.parent.fileBateauAChasser.isEmpty()){
                    char codeBateauTouche  = this.parent.listeBateaux[this.parent.fileBateauAChasser.element()].getCodeTouche();
                    int[] coordBateau = new int[2];
                    coordBateau = this.parent.connaissanceIA.chercheBateau(codeBateauTouche);
                    if (coordBateau == null)
                        throw new NullPointerException("Bateau "+codeBateauTouche+" non retrouvé");
                    this.parent.fileCaseAJouer.add(coordBateau);
                    break;
                }
                //Si on aucun bateau a chasser et aucune case a jouer
                else if (this.parent.fileCaseAJouer.isEmpty() && this.parent.fileBateauAChasser.isEmpty()){
                    joueAleatoire();
                    break;
                }

            default:
                break;
        }
    }

    /**
     * this.consequence == 1
     *
     *
     * @return les coordonnees a jouer
     */
    public void joueAleatoire(){
        int[] coordAJouer = new int[2];
        coordAJouer[0] = this.parent.getRandomNum(0, 9);
        coordAJouer[1] = this.parent.getRandomNum(0, 9);

        this.parent.fileCaseAJouer.add(coordAJouer);
    }


    //AFFICHAGE EN CONSOLE SEULEMENT
    /**
     * Informe sur l'état actuel du jeu (avec les preconditions mises en place)
     * cette methode n'est pas specifique a un objet
     *
     * @param r
     */
    public void testPrecondition() {
        System.out.println("Manque : " + this.aManque());
        System.out.println("Touche : " + this.estTouche());
        System.out.println("Coule : " + this.estCoule());
        System.out.println("bateauTouche : " + this.aBateauTouche());
    }

    /**
     * Informe sur les preconditions de la règle
     *
     */
    public void printPrecondition() {
        System.out.println("Manque : " + this.manque);
        System.out.println("Touche : " + this.touche);
        System.out.println("Coule : " + this.coule);
        System.out.println("bateauTouche : " + this.bateauTouche);
    }
}


